package com.web.exiaodao.remote.controller;

import com.alipay.config.AlipayConfig;
import com.alipay.util.AlipayNotify;
import com.alipay.util.OrderInfoUtil2_0;
import com.web.exiaodao.business.constant.JConstant;
import com.web.exiaodao.business.entity.User;
import com.web.exiaodao.business.entity.WalletRechargeRecord;
import com.web.exiaodao.business.repository.UserRepository;
import com.web.exiaodao.business.repository.WalletRechargeRecordRepository;
import com.web.exiaodao.business.service.ReturnshoprecordService;
import com.web.exiaodao.remote.service.ApiOrderService;
import com.web.exiaodao.remote.service.ApiUserService;
import com.web.exiaodao.remote.service.ApiWalletRechargeRecordService;
import com.web.exiaodao.remote.service.ApiWalletTradeRecordService;
import com.web.exiaodao.remote.vo.ConfigurationTableVo;
import com.web.exiaodao.remote.vo.OrderVo;
import com.web.exiaodao.remote.vo.UserVo;
import com.web.webstart.base.constant.XaConstant;
import com.web.webstart.base.controller.BaseController;
import com.web.webstart.base.exception.BusinessException;
import com.web.webstart.base.util.XaUtil;
import com.web.webstart.base.util.result.XaResult;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import static com.web.exiaodao.business.constant.JConstant.SERVER_ADDRESS;
import static com.web.exiaodao.business.constant.JConstant.SERVER_NAME;

/**
 * @author zhanglin
 * @version V1.0
 * @Title: ApiAlipayNotifyController.java
 * @Package com.web.liuda.remote.controller
 * @Description: 支付宝接口
 * @date 2015年3月23日 下午1:00:00
 */
@Api(value = "pay_alipaay", description = "支付宝", position = 10)
@Controller
@RequestMapping("/api/alipay")
public class ApiPayAlipayController extends BaseController {

    private static final Logger LOGGER = Logger.getLogger(ApiOrderController.class);

    @Autowired
    ApiOrderService orderService;

    //订单退款表
    @Autowired
    private ReturnshoprecordService refundOrderService;

    @Autowired  //充值订单
    private WalletRechargeRecordRepository walletRechargeRecordRepository;
    @Autowired
    private ApiWalletRechargeRecordService walletRechargeRecordService;
    @Autowired
    private ApiWalletTradeRecordService walletTradeRecordService;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private ApiUserService userService;

    /**
     * @ClassName: 获取支付宝支付的订单字符串;以前是app自己获取,现在后台获取
     * @Description: app 请求参数 新版放到后台生成 https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.x7kkCI&treeId=204&articleId=105465&docType=1
     * 支付宝更新日期:更新时间：2016/08/31
     * 注意修改支付宝参数 {@link AlipayConfig}
     * 这个方法的所有代码来自android 或者 ios客户端代码
     * @author duandazhi
     * @date 2016/11/21 下午6:44
     */
    @ApiOperation(value = "获取支付宝支付的订单字符串", notes = "支付宝字符串")
    @ResponseBody
    @RequestMapping(value = "getOrderStr", method = RequestMethod.POST)
    public XaResult<String> getOrderStr(
            @ApiParam("订单编号,字段名:orderNo") @RequestParam(value = "orderNo") String orderNo,
            @ApiParam("类型,字段名:type;1:普通订单:2:钱包充值订单；3：充值成为vip订单") @RequestParam(value = "type") Integer type,
            @ApiParam("userId,字段名:mobile;vip订单需要传递userId") @RequestParam(value = "userId", required = false) String userId,
            HttpServletRequest request,
            HttpServletResponse reponse
    ) throws Exception {
        XaResult<String> xr = new XaResult<>();
        if (XaUtil.isEmpty(orderNo)) {
            xr.error("订单id不能为空!");
            return xr;
        }
        try {
            String ordertPrice = "";
            String ordertSubject = "";

            //常规订单
            if (type == 1) {
                //获取订单信息
                XaResult<OrderVo> orderXr = orderService.findOrderInfoByOrderNo(orderNo);
                OrderVo orderVo = orderXr.getObject();
                if (Integer.parseInt(orderVo.getOrderState()) == JConstant.OrderStatus.PAYED) {
                    xr.error("你的订单已经支付,请不要重复支付!");
                    return xr;
                }
                if (Integer.parseInt(orderVo.getOrderState()) != JConstant.OrderStatus.UN_PAY) {
                    xr.error("只有待支付的订单才能支付,请检查");
                    LOGGER.error("(alipay)" + xr.getMessage() + ";orderNo:" + orderNo + ",订单状态:" + JConstant.OrderStatus.UN_PAY, null);
                    return xr;
                }
                ordertPrice = orderXr.getObject().getOrderTotalPirce() + "";
                ordertSubject = XaUtil.getNutNullStr(orderXr.getObject().getOrderName(), "subject");
            } else if (type == 2) {
                //钱包充值订单
                WalletRechargeRecord walletRechargeRecord = walletRechargeRecordRepository.findByRechargeOrderNo(orderNo);
                if (XaUtil.isEmpty(walletRechargeRecord)) {
                    xr.error("钱包充值订单不存在：" + orderNo);
                    return xr;
                }
                ordertPrice = walletRechargeRecord.getRechargeMoney() + "";
                ordertSubject = "账号钱包充值";
            } else {
                //vip订单充值
                if (XaUtil.isEmpty(userId)) {
                    xr.error("userId不能我空！");
                    return xr;
                }
                UserVo userVo = userService.findOne(XaUtil.getNutNullLong(userId, 0l)).getObject();
                boolean isVip = XaUtil.getBool(userVo.getVip());
                if (isVip) {
                    xr.error("您已经是vip账号请不要重复充值！");
                    return xr;
                }
                if (XaUtil.isEmpty(userVo.getVipOrderNo())) {
                    xr.error("请先获取vip订单号！");
                    return xr;
                }
                ConfigurationTableVo configurationTableVo = userVo.getConfigurationVo();
                if (configurationTableVo == null || configurationTableVo.getVipPrice() == null) {
                    throw new BusinessException(XaConstant.Message.object_not_config);
                }
                if (configurationTableVo.getVipPrice().doubleValue() <= 0) {
                    xr.error("成为vip价格不能小于等于0!");
                    return xr;
                }
                orderNo = userVo.getVipOrderNo();
                ordertPrice = configurationTableVo.getVipPrice() + "";
                ordertSubject = "vip账户充值";
            }
            /**
             * 这里只是为了方便直接向商户展示支付宝的整个支付流程；所以Demo中加签过程直接放在客户端完成；
             * 真实App里，privateKey等数据严禁放在客户端，加签过程务必要放在服务端完成；
             * 防止商户私密数据泄露，造成不必要的资金损失，及面临各种安全风险；
             *
             * orderInfo的获取必须来自服务端；
             * https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.wH9VMF&treeId=193&articleId=105465&docType=1
             *
             */
            String nofity_url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/" + SERVER_NAME + "/api/alipay/notify";
            //1. 请求参数按照key=value&key=value方式拼接的未签名原始字符串：
            Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(
                    orderNo,
                    ordertPrice,
                    ordertSubject, //商品标题
                    "body",
                    JConstant.ENV == 1 ? nofity_url : SERVER_ADDRESS + SERVER_NAME + "/api/alipay/notify"
            );//商品详细的信息
            String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
            String sign = OrderInfoUtil2_0.getSign(params, AlipayConfig.RSA_PRIVATE);
            final String orderInfo = orderParam + "&" + sign;
            xr.setObject(orderInfo);
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                xr.error(e.getMessage());
            } else {
                xr.error(XaConstant.Message.error);
            }
            LOGGER.error(XaConstant.Message.error, new Throwable(e));
        }
        return xr;
    }


    /**
     * @return
     * @Title: notify
     * @Description: 异步通知 见 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.MBGyJk&treeId=59&articleId=103563&docType=1 demo中的notify_url
     * 异步,同步通知的频率方式 见 "服务器异步通知参数说明"
     * or  https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.AaFBF9&treeId=193&articleId=105301&docType=1#s6
     */
    @SuppressWarnings("rawtypes")
    @ApiOperation(value = "异步通知", notes = "异步通知")
    @ResponseBody
    @RequestMapping(value = "notify", method = RequestMethod.POST)
    public void notify(
            HttpServletRequest request,
            HttpServletResponse reponse
    ) throws Exception {
        reponse.reset();
        PrintWriter out = reponse.getWriter();
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }
        String gmt_create = params.get("gmt_create");//"gmt_create" -> "2016-11-27 16:23:45"
        //使用 服务端SDK -->SDK1.5 进行验证 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.auVSbr&treeId=193&articleId=103419&docType=1
        //https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.auVSbr&treeId=193&articleId=103419&docType=1#s5
        if (AlipayNotify.verify(params)) {//验证成功  1:自己写的方法
            //交易状态
            String trade_status = params.get("trade_status");
            //交易成功后执行的业务代码
            if (trade_status.equals("TRADE_FINISHED")) {

            } else if (trade_status.equals("TRADE_SUCCESS")) {//支付成功后执行的业务代码
                String out_trade_no = params.get("out_trade_no");//订单号
                String total_fee = params.get("total_amount");//订单金额
                String trade_no = params.get("trade_no");//支付宝交易号(退款用)

                if (out_trade_no.length() == 16) {//常规订单16位
                    orderService.modifyOrder(out_trade_no, total_fee, trade_no, JConstant.PayType.ALIPAY);
                } else if (out_trade_no.length() == 12) {
                    //充值订单12位
                    walletRechargeRecordService.modifyRechargeOrder(out_trade_no, total_fee, trade_no, JConstant.PayType.ALIPAY);
                } else {
                    //生成vip订单号14位
                    User user = userRepository.findByVipOrderNo(out_trade_no);
                    user.setVip(true);
                    userRepository.save(user);
                }
            }
            out.println("success");    //请不要修改或删除;sucess通知支付宝商户已经处理好了
        } else {//验证失败
            out.println("fail");
        }
    }

    /**
     * @return
     * @Title: notifyRefund
     * @Description: 退款通知
     */
    @SuppressWarnings("rawtypes")
    @ApiOperation(value = "异步通知(退款)", notes = "支付宝退款通知")
    @ResponseBody
    @RequestMapping(value = "notifyRefund", method = RequestMethod.POST)
    public void alipayNotify(
            HttpServletRequest request,
            HttpServletResponse reponse
    ) throws Exception {
        LOGGER.info("支付宝-退款通知开始");
        reponse.reset();
        PrintWriter out = reponse.getWriter();
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }
        // TODO:dz 2017/1/24
//        if (AlipayNotify.verify(params)) {//验证成功
        LOGGER.info("验签成功！");
        //////////////////////////////////////////////////////////////////////////////////////////
        //请在这里加上商户的业务逻辑程序代码

        //——请根据您的业务逻辑来编写程序（以下代码仅作参考）——

        //判断是否在商户网站中已经做过了这次通知返回的处理
        //如果没有做过处理，那么执行商户的业务程序
        //如果有做过处理，那么不执行商户的业务程序

        //批量退款数据中的详细信息
        String result_details = new String(request.getParameter("result_details").getBytes("ISO-8859-1"), "UTF-8");
        String[] arr = result_details.split("\\^");
        if (arr.length > 0) {
            String r = orderService.modifyOrderRefund(arr[0], JConstant.OrderRefundStatus.REFUND_SUCCESS, JConstant.PayType.ALIPAY);
            if ("0000".equals(r)) {
                out.println("success");    //请不要修改或删除
                LOGGER.info("验签成功！退款成功！");
            } else {
                out.println("fail");
                LOGGER.info("验签成功！退款失败！");
            }
        }
//        }
//        else {//验证失败
//            LOGGER.info("验签失败！");
//            out.println("fail");
//        }
    }

    /**
     * @return
     * @Title: notifyWithdraw
     * https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.j0voyu&treeId=64&articleId=104804&docType=1
     * @Description: 批量付款/提现 通知
     */
    @SuppressWarnings("rawtypes")
    @ApiOperation(value = "批量付款/提现 ", notes = "批量付款/提现异步通知")
    @ResponseBody
    @RequestMapping(value = "notifyWithdraw", method = RequestMethod.POST)
    public void notifyWithdraw(
            HttpServletRequest request,
            HttpServletResponse reponse
    ) throws Exception {
        LOGGER.info("支付宝-批量付款/提现 通知 开始");
        reponse.reset();
        PrintWriter out = reponse.getWriter();
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }

        // TODO:dz 2017/1/24
//        if (AlipayNotify.verify(params)) {//验证成功

        //批次号
        String batch_no = params.get("batch_no");
        String success_details = params.get("success_details");
        ;
        String fail_details = params.get("fail_details");//批量付款数据中转账失败的详细信息

        System.out.println("付款结果sucess：" + success_details);//付款结果sucess：2017020713570542066^13571666197^???^0.01^S^^201702070177324006^20170207174850|
        System.out.println("付款结果fail：" + fail_details);
        System.out.println("付款批次号：" + batch_no);//付款批次号：2017020717485490315

        String[] sucessArr = success_details != null ? success_details.split("\\|") : null;
        String[] failArr = fail_details != null ? fail_details.split("\\|") : null;
        if ((sucessArr != null && sucessArr.length > 0) || (failArr != null && failArr.length > 0)) {

            boolean isHaveErro = false;
            try {
                for (int i = 0; sucessArr != null && i < sucessArr.length; ++i) {
                    if (XaUtil.isNotEmpty(sucessArr[i])) {
                        String flowId = sucessArr[i].split("\\^")[0];
                        walletTradeRecordService.widthdrawSucess(flowId);
                    }
                }
                for (int j = 0; failArr != null && j < failArr.length; ++j) {
                    if (XaUtil.isNotEmpty(failArr[j])) {
                        String flowId = failArr[j].split("\\^")[0];//流水号
                        //String errorMsg = failArr[j].split("\\^")[5];//失败原因
                        String errorMsg = failArr[j];//失败原因
                        walletTradeRecordService.widthdrawFail(flowId, errorMsg);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                LOGGER.error(e.getMessage(), e);
                isHaveErro = true;
            }

            if (!isHaveErro) {
                out.println("success");    //请不要修改或删除
                LOGGER.info("验签成功！批量付款操作完成！");
            } else {
                out.println("fail");
                LOGGER.info("验签失败！批量付款操作失败！");
            }
        }
    }
//        else {//验证失败
//            LOGGER.info("验签失败！");
//            out.println("fail");
//        }
//    }
}
